package com.sj.purchase.modules.cost.service;

import com.sj.purchase.modules.cost.domain.imei.UniqueCodes;
import com.sj.purchase.modules.cost.repository.imei.UniqueCodesRepository;
import com.sj.purchase.modules.cost.views.uniquecode.Orders;
import com.sj.purchase.util.DateUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;
import java.util.stream.Collectors;

/**
 * 描述:
 * 作者: cuijh
 * 包名：com.sj.purchase.modules.cost.service
 * 日期: 2018年07月11日 17:26
 * 项目名称: purchase
 */
@Service
public class UniqueCodeService {

    @PersistenceContext
    private EntityManager manager;

    @Autowired
    private UniqueCodesRepository repository;

    private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static final Logger LOGGER = LoggerFactory.getLogger(UniqueCodeService.class);

    /**
     * 自动获取唯一码相关数据
     * @return
     */
    public void saveUniqueCode(Date date){
        LOGGER.info("自动导入数据开始时间："+format.format(new Date()));
        try {
            String start = format.format(DateUtils.getStart(date));
            String end = format.format(DateUtils.getEnd(date));
            List<UniqueCodes> uniqueCodes = new ArrayList<>();
            String sql = "SELECT x.* FROM (SELECT m.*, i.supplier_name FROM t_in_order i RIGHT JOIN (SELECT out_order_no trades_id,in_order_no,sku_no sku_id,shop_name,sku_name,imei ucode,cost_price,in_stock_date,out_stock_date FROM t_inventory WHERE out_stock_date >= '"+start+"' AND out_stock_date <= '"+end+"' AND shop_name IN ('三际数码官方旗舰店','华为天鹰专卖店','三星手机专卖店')) m ON m.in_order_no = i.order_no) x LEFT JOIN (SELECT t.order_no,d.sku_no FROM t_out_order t LEFT JOIN t_out_order_details d ON t.id = d.order_id WHERE create_date >= '"+start+"' AND create_date <= '"+end+"') n ON x.trades_id LIKE n.order_no AND x.sku_id = n.sku_no";
            Query query = manager.createNativeQuery(sql);
            List<Object[]> result = query.getResultList();
            for (Object[] o:result) {
                UniqueCodes uniqueCode = new UniqueCodes();
                if(ObjectUtils.allNotNull(o[0])){uniqueCode.setTradesId(o[0].toString());}
                if(ObjectUtils.allNotNull(o[1])){uniqueCode.setInOrderNo(o[1].toString());}
                if(ObjectUtils.allNotNull(o[2])){uniqueCode.setSku_id(o[2].toString());}
                if(ObjectUtils.allNotNull(o[3])){uniqueCode.setShopName(o[3].toString());}
                if(ObjectUtils.allNotNull(o[4])){uniqueCode.setSku_name(o[4].toString());}
                if(ObjectUtils.allNotNull(o[5])){uniqueCode.setUcode(o[5].toString());}
                if(ObjectUtils.allNotNull(o[6])){uniqueCode.setCostPrice((Double)o[6]);}
                if(ObjectUtils.allNotNull(o[7])){uniqueCode.setInStockDate((Date)o[7]);}
                if(ObjectUtils.allNotNull(o[8])){uniqueCode.setOutStockDate((Date)o[8]);}
                if(ObjectUtils.allNotNull(o[9])){ uniqueCode.setSupplierName(o[9].toString()); }
                uniqueCodes.add(uniqueCode);
            }
            repository.save(uniqueCodes);
            LOGGER.info("自动导入数据正常结束时间："+format.format(new Date())+"总数据："+uniqueCodes.size()+"条");
        }catch (Exception e){
            LOGGER.info("自动导入数据异常结束时间："+format.format(new Date()));
        }
    }

    /**
     * 从上传表中获取添加orderId的字段数据
     * @param date
     * @param ordersList
     * @return
     */
    public List<UniqueCodes> checkUniqueCodes(String date,List<Orders> ordersList){
        LOGGER.info("数据处理开始时间："+format.format(new Date()));
        Date start = DateUtils.getStart(DateUtils.dateFormat(date));
        Date end = DateUtils.getEnd(DateUtils.dateFormat(date));
        Page<UniqueCodes> uniqueCodesPage = repository.findByOutStockDateBetween(start,end,null);
        List<UniqueCodes> uniqueCodes = uniqueCodesPage.getContent();
        Map<String,List<UniqueCodes>> map = split(uniqueCodes);
        Map<Key, List<Orders>> ordersMap = toMap(ordersList);
        LOGGER.info("数据处理结束时间："+format.format(new Date()));
        return format1(map,ordersMap);
    }

    /**
     * 拆分现有数据为正常数据和异常数据
     * @param uniqueCodes
     * @return
     */
    private Map<String,List<UniqueCodes>> split(List<UniqueCodes> uniqueCodes){
        List<UniqueCodes> list1 = new ArrayList<>();//保存正常数据
        List<UniqueCodes> list2 = new ArrayList<>();//保存异常数据
        uniqueCodes.forEach(uniqueCode -> {
            String tradesId = uniqueCode.getTradesId();
            if(tradesId.indexOf(",") == -1){
                list1.add(uniqueCode);
            }else {
                String[] tradesIds = uniqueCode.getTradesId().split(",");
                for (String id : tradesIds) {
                    UniqueCodes uniqueCode1 = new UniqueCodes();
                    uniqueCode1.setTradesId(id);
                    uniqueCode1.setUcode(uniqueCode.getUcode());
                    uniqueCode1.setSku_id(uniqueCode.getSku_id());
                    uniqueCode1.setSku_name(uniqueCode.getSku_name());
                    uniqueCode1.setShopName(uniqueCode.getShopName());
                    uniqueCode1.setOutStockDate(uniqueCode.getOutStockDate());
                    uniqueCode1.setInStockDate(uniqueCode.getInStockDate());
                    uniqueCode1.setCostPrice(uniqueCode.getCostPrice());
                    uniqueCode1.setSupplierName(uniqueCode.getSupplierName());
                    uniqueCode1.setInOrderNo(uniqueCode.getInOrderNo());
                    list2.add(uniqueCode1);
                }
            }
        });
        Map<String,List<UniqueCodes>> map = new HashMap<>();
        map.put("normal",list1);
        map.put("abnormal",list2);
        return map;
    }

    private Map<Key, List<Orders>> toMap(List<Orders> a){
        return a.stream().collect(Collectors.groupingBy(o->new Key(o.getTradesId(),o.getSku_id())));
    }

    /**
     * 唯一码数据对比订单数据获取所需数据
     * @param map
     * @param orders
     * @return
     */
    private List<UniqueCodes> format1(Map<String,List<UniqueCodes>> map,Map<Key, List<Orders>> orders){
        List<UniqueCodes> uniqueCodes = map.get("normal");
        //正常唯一码数据匹配
        List<UniqueCodes> uniqueCodesList = new ArrayList<>();
        uniqueCodes.forEach(uniqueCode -> {
            Key key = new Key(uniqueCode.getTradesId(), uniqueCode.getSku_id());
            if(null != orders.get(key)){
                if (orders.containsKey(key)) {
                    List<Orders> ordersList = orders.get(key);UniqueCodes uniqueCodes1 = new UniqueCodes(uniqueCode,uniqueCode.getTradesId());
                    uniqueCodes1.setOrderId(ordersList.get(0).getOrderId());
                    uniqueCodesList.add(uniqueCodes1);
                }
            }
        });
        List<UniqueCodes> list = map.get("abnormal");
        Set<String> set = new HashSet<>();
        Set<String> ucode = new HashSet<>();
        //异常唯一码数据匹配
        list.forEach(uniqueCode -> {
            //保存交易号字段与规格编号
            set.add(uniqueCode.getTradesId()+uniqueCode.getSku_id());
            //保存唯一码
            ucode.add(uniqueCode.getUcode());
        });
        //订单数据中当商品数量大于1时存入k交易号规格编号，v商品数量
        Map<String,Integer> map1 = new HashMap<>();
        //异常唯一码数据匹配
        for (UniqueCodes uniqueCode:list) {
            String str = uniqueCode.getTradesId()+uniqueCode.getSku_id();
            Key key = new Key(uniqueCode.getTradesId(),uniqueCode.getSku_id());
            if(null != orders.get(key) && ucode.contains(uniqueCode.getUcode())){
                if (orders.containsKey(key)) {
                    List<Orders> ordersList = orders.get(key);
                    ordersList.forEach(order -> {
                        UniqueCodes uniqueCodes1 = new UniqueCodes(uniqueCode,uniqueCode.getTradesId());
                        uniqueCodes1.setOrderId(order.getOrderId());
                        if(checkNum(str,order,map1)){
                            set.remove(str);
                            ucode.remove(uniqueCode.getUcode());
                        }
                        uniqueCodesList.add(uniqueCodes1);
                    });
                }
            }
        }
        try {
            return uniqueCodesList;
        }catch (Exception e){
            return null;
        }
    }

    /**
     * 判断是否移除set中相关字段
     * @param str
     * @param order
     * @param map
     * @return
     */
    private Boolean checkNum(String str, Orders order,Map<String,Integer> map){
        //根据交易号规格编号获取商品数量无记录则根据订单数据判读数量
        if(map.get(str) == null){
            //商品数量大于1保存与map集合并且实时更新商品已匹配的数量，商品不大于1时返回true
            Integer num = Integer.parseInt(order.getNumber()) > 1?Integer.parseInt(order.getNumber()):0;
            if (num == 0){
                return true;
            }else {
                num = num - 1;
                map.put(str,num);
                return false;
            }
        }
        //根据交易号规格编号获取商品数量，数量大于1返回false
        else if(map.get(str) > 1){
            Integer num = map.get(str) - 1;
            map.put(str,num);
            return false;
        }else {
            return true;
        }
    }

    class Key{
        String skuNo;
        String tradesNo;

        public Key(String tradesNo, String skuNo) {
            this.tradesNo = tradesNo;
            this.skuNo = skuNo;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Key key = (Key) o;

            if (skuNo != null ? !skuNo.equals(key.skuNo) : key.skuNo != null) return false;
            return tradesNo != null ? tradesNo.equals(key.tradesNo) : key.tradesNo == null;
        }

        @Override
        public int hashCode() {
            int result = skuNo != null ? skuNo.hashCode() : 0;
            result = 31 * result + (tradesNo != null ? tradesNo.hashCode() : 0);
            return result;
        }
    }
}
